package nsip.components.ds;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import nsip.util.LazyInitializingMap;

public class Inventory extends LazyInitializingMap<Integer, Integer> {

    private boolean allowNegative = false;

    public Inventory() {}
    
    public Inventory(boolean allowNegative) {
        this.allowNegative = allowNegative;
    }

    public Inventory(Map<Integer, Integer> m) {
        super(m);
    }

    @Override
    protected Integer initialize(Object key) {
        return 0;
    }

    @Override
    public Integer put(Integer key, Integer value) {
        if (!allowNegative && value < 0) {
            throw new IllegalArgumentException(
                "Can not have negative amount in inventory");
        }
        return super.put(key, value);
    }

    /**
     * Returns true if this inventory holds all components with the specified
     * quantity.
     * 
     * @param components
     * @param quantity
     * @return
     */
    public boolean containsComponents(Integer[] keys, int quantity) {
        for (Integer key: keys) {
            if (get(key) < quantity) {
                return false;
            }
        }
        return true;
    }

    /**
     * Returns true if this inventory contains the specified quantity of the
     * key.
     * 
     * @param productID
     * @param quantity
     * @return
     */
    public boolean contains(int key, int quantity) {
        return get(key) > quantity;
    }
    
    /**
     * Tries to decreas the number of products in the inventory
     * by the given amount
     *
     * @param key
     * @param amount
     *
     * @return amount of values actually decreased;
     */
    public boolean remove(Integer key, int amount) {
        Integer value = get(key);
        if (!allowNegative && value < amount) {
            return false;
        } else {
            put(key, value - amount);
            return true;
        }
    }

    /**
     * Increases the inventory by the specified amount
     * @param key
     * @param amount
     */
    public void add(Integer key, int amount) {
        Integer value = get(key);
        put(key, value + amount);
    }

    /**
     * Return products in this inventory map
     * @return
     */
    public Collection<Integer> getEntriesAvailable() {
        Set<Integer> result = new HashSet();
        for (Map.Entry<Integer, Integer> e : entrySet()) {
            if (e.getValue() > 0) {
                result.add(e.getKey());
            }
        }
        return result;
    }

    /**
     * Adds the amount of products to this inventory
     * 
     * @param keys
     * @param amount
     */
    public void addAll(int[] keys, int amount) {
        for (Integer productID: keys) {
            add(productID, amount);
        }
    }
}
